﻿//using DotNetCommon;
//using DotNetCommon.Extensions;
//using NUnit.Framework;
//using System;
//using System.Collections.Generic;
//using System.Diagnostics;
//using System.Linq;
//using System.Text;
//using System.Threading;
//using System.Threading.Tasks;

//namespace Test.SqlServer
//{
//    /// <summary>
//    /// 测试Id和流水号生成,基于数据库缓存
//    /// </summary>
//    [TestFixture]
//    public sealed partial class GeneratorTests : TestBase
//    {
//        private void ClearDBCache()
//        {
//            db.Manage.DropTableIfExist(db.Settings.DBCacheGeneratorIdTableName);
//            db.Manage.DropTableIfExist(db.Settings.DBCacheGeneratorSNOTableName);
//            db.Manage.DropTableIfExist(db.Settings.DBCacheGeneratorLogTableName);
//            db.Manage.DropProcedureIfExist(db.Settings.DBCacheGeneratorIdProcedureName);
//            db.Manage.DropProcedureIfExist(db.Settings.DBCacheGeneratorSNOProcedureName);
//        }
//        #region Id生成中的各种情况测试
//        /// <summary>
//        /// 当表不存在报错时
//        /// </summary>
//        [Test]
//        public void TestNoTableError()
//        {
//            ClearDBCache();
//            db.Manage.DropTableIfExist("test5");
//            try
//            {
//                var id = db.NewId("test5", "id");
//                throw new Exception("竟然没报错!");
//            }
//            catch (Exception ex)
//            {
//                int i = 0;
//            }
//        }

//        /// <summary>
//        /// 当表中还没有数据时
//        /// </summary>
//        [Test]
//        public void TestTableHasNoData()
//        {
//            ClearDBCache();
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql("create table test(id int primary key,name varchar(50))");
//            var id = db.NewId("test", "id");
//            Assert.IsTrue(id == 1);
//            id = db.NewId("test", "id");
//            Assert.IsTrue(id == 2);
//        }

//        /// <summary>
//        /// 当表中已有数据时
//        /// </summary>
//        [Test]
//        public void TestTableHasData()
//        {
//            ClearDBCache();
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql("create table test(id int primary key,name varchar(50))");
//            db.Insert("test", new { id = 1, name = "小明" }.ToDictionary());
//            var id = db.NewId("test", "id");
//            Assert.IsTrue(id == 2);
//            id = db.NewId("test", "id");
//            Assert.IsTrue(id == 3);
//        }

//        /// <summary>
//        /// 当表中已有缓存时
//        /// </summary>
//        [Test]
//        public void TestHasDataCache()
//        {
//            ClearDBCache();
//            db.ExecuteSql(@"
//CREATE TABLE [dbo].[__generator_id](
//	[tablename] [varchar](50) NOT NULL,
//	[colname] [varchar](50) NOT NULL,
//	[currentid] [bigint] NULL,
//PRIMARY KEY CLUSTERED 
//(
//	[tablename] ASC,
//	[colname] ASC
//)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
//) ON [PRIMARY]");
//            db.Insert("__generator_id", new { tablename = "test", colname = "id", currentid = 5 }.ToDictionary());
//            var id = db.NewId("test", "id");
//            Assert.IsTrue(id == 6);
//            id = db.NewId("test", "id");
//            Assert.IsTrue(id == 7);
//        }

//        /// <summary>
//        /// 测试未获取到锁超时
//        /// </summary>
//        [Test]
//        public void TestErrorTimeout()
//        {
//            ClearDBCache();
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql("create table test(id int primary key,name varchar(50))");
//            var id = db.NewId("test", "id");
//            Assert.IsTrue(id == 1);

//            //制造一个锁 30秒
//            var task1 = Task.Run(() =>
//              {
//                  try
//                  {
//                      var newDb = db.CreateNewDB();
//                      newDb.RunInTransaction(() =>
//                      {
//                          newDb.ExecuteSql(@"
//declare @result int=1;
//EXEC @result =sp_getAppLock @resource='dbutil:newid:test_id',@lockMode='Exclusive',@lockOwner='Transaction',@lockTimeout='60000';
//select @result");
//                          Thread.Sleep(25 * 1000);
//                      });
//                  }
//                  catch (Exception ex)
//                  {
//                      //不应该报错
//                      throw ex;
//                  }
//              });
//            var task2 = Task.Run(() =>
//            {
//                try
//                {
//                    Thread.Sleep(1000);
//                    var id = db.NewId("test", "id");
//                    throw new Exception("应该报超时的错!");
//                }
//                catch (Exception ex)
//                {
//                    //锁超时信息
//                    Assert.IsTrue(ex.Message.Contains("20秒内"));
//                }
//            });
//            Task.WaitAll(task1, task2);
//        }
//        #endregion

//        #region Id生成
//        [Test]
//        public void NewId_DBCacheTest()
//        {
//            ClearDBCache();
//            //准备测试表
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql(@"create table test(
//id int primary key,
//name varchar(50)
//)");
//            //单个id生成
//            long id = db.NewId("test", "id");
//            Assert.IsTrue(id == 1);
//            id = db.NewId("test", "id");
//            Assert.IsTrue(id == 2);
//            //根据表中已有的id,继续生成
//            db.ResetId("test", "id");
//            var dic = new Dictionary<string, object>();
//            dic.Add("id", 5);
//            dic.Add("name", "xiaoming" + id);
//            db.Insert("test", dic);
//            id = db.NewId("test", "id");
//            Assert.IsTrue(id == 6);
//            //根据缓存批量生成id
//            db.ResetId("test", "id");
//            db.Manage.TruncateTable("test", "dbo");
//            dic = new Dictionary<string, object>();
//            dic.Add("id", 2);
//            dic.Add("name", "xiaoming" + id);
//            db.Insert("test", dic);
//            id = db.NewId("test", "id");
//            Assert.IsTrue(id == 3);
//            var ids = db.NewIds("test", "id", 5);
//            var expect = new List<long>() { 4, 5, 6, 7, 8 };
//            var expectStr = string.Join(",", expect);
//            var actStr = string.Join(",", ids);
//            Assert.IsTrue(expectStr == actStr);
//            //根据表中已有的id,继续批量生成
//            db.ResetId("test", "id");
//            ids = db.NewIds("test", "id", 5);
//            expect = new List<long>() { 3, 4, 5, 6, 7 };
//            expectStr = string.Join(",", expect);
//            actStr = string.Join(",", ids);
//            Assert.IsTrue(expectStr == actStr);
//            //直接从缓存中生成
//            db.Manage.TruncateTable("test", "dbo");
//            db.ResetId("test", "id");
//            ids = db.NewIds("test", "id", 5);
//            expect = new List<long>() { 1, 2, 3, 4, 5 };
//            expectStr = string.Join(",", expect);
//            actStr = string.Join(",", ids);
//            Assert.IsTrue(expectStr == actStr);
//        }

//        [Test]
//        public void NewIdConcurrency_DBCacheTest()
//        {
//            ClearDBCache();
//            //准备测试表
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql(@"create table test(
//id int primary key,
//name varchar(50)
//)");
//            var tasks = new List<Task>();
//            var idres = new System.Collections.Concurrent.ConcurrentQueue<(long id, int threadid)>();
//            for (int i = 0; i < 100; i++)
//            {
//                tasks.Add(Task.Factory.StartNew(() =>
//                {
//                    try
//                    {
//                        var db2 = db.CreateNewDB();
//                        for (int j = 0; j < 100; j++)
//                        {
//                            var idg = db2.NewId("test", "id");
//                            idres.Enqueue((idg, Thread.CurrentThread.ManagedThreadId));
//                        }
//                    }
//                    catch (Exception ex)
//                    {
//                        Debug.Write(ex?.Message + ex?.StackTrace);
//                        Debug.Fail(ex?.Message, ex?.StackTrace);
//                    }
//                }, TaskCreationOptions.LongRunning));
//            }
//            Task.WaitAll(tasks.ToArray());
//            var list = idres.ToList();
//            list = list.OrderByDescending(t => t.id).ToList();
//            var expactCount = 100 * 100;
//            Assert.IsTrue(list.LastOrDefault().id == 1);
//            Assert.IsTrue(list.FirstOrDefault().id == expactCount);
//            Assert.IsTrue(list.Count == expactCount);
//        }
//        #endregion

//        #region SNO生成中的各种情况测试
//        /// <summary>
//        /// 表不存在,报错
//        /// </summary>
//        [Test]
//        public void TestErrorSql()
//        {
//            ClearDBCache();
//            db.Manage.DropTableIfExist("test");
//            try
//            {
//                var sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//                throw new Exception("竟然没报错!");
//            }
//            catch (Exception ex)
//            {
//                int i = 0;
//            }
//        }

//        /// <summary>
//        /// 无缓存 表中没有匹配数据
//        /// </summary>
//        [Test]
//        public void TestNoCacheNoData()
//        {
//            ClearDBCache();
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql("create table test(sno varchar(50))");
//            var sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//            Assert.IsTrue(sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}000001");
//            sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//            Assert.IsTrue(sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}000002");
//        }

//        /// <summary>
//        /// 无缓存 表中有匹配数据
//        /// </summary>
//        [Test]
//        public void TestNoCacheHasData()
//        {
//            ClearDBCache();
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql("create table test(sno varchar(50))");
//            db.Insert("test", new { sno = $"SNO{DateTime.Now.ToString("yyyyMMdd")}000005" }.ToDictionary());
//            var sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//            Assert.IsTrue(sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}000006");
//            sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//            Assert.IsTrue(sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}000007");
//        }

//        /// <summary>
//        /// 有缓存,时间戳对不上
//        /// </summary>
//        [Test]
//        public void TestHasCacheWrongTimeStamp()
//        {
//            ClearDBCache();
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql(@"
//create table __generator_sno
//(
//	tablename varchar(50),
//	colname varchar(50),
//	statictext varchar(200),
//	machineidstr varchar(50),
//	nowstr varchar(100),
//	currentno bigint,
//	primary key(tablename,colname,statictext)
//)");
//            db.Insert("__generator_sno", new { tablename = "test", colname = "sno", statictext = $"SNO", nowstr = DateTime.Now.AddDays(-1).ToCommonString(), currentno = "2" }.ToDictionary());
//            var sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));

//            Assert.IsTrue(sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}000001");
//            sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//            Assert.IsTrue(sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}000002");
//        }

//        /// <summary>
//        /// 有缓存,时间戳对得上
//        /// </summary>
//        [Test]
//        public void TestHasCacheRightTimeStamp()
//        {
//            ClearDBCache();
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql(@"
//create table __generator_sno
//(
//	tablename varchar(50),
//	colname varchar(50),
//	statictext varchar(200),
//	machineidstr varchar(50),
//	nowstr varchar(100),
//	currentno bigint,
//	primary key(tablename,colname,statictext)
//)");
//            db.Insert("__generator_sno", new { tablename = "test", colname = "sno", statictext = $"SNO", nowstr = DateTime.Now.ToString("yyyyMMdd"), currentno = "2" }.ToDictionary());
//            var sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));

//            Assert.IsTrue(sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}000003");
//            sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//            Assert.IsTrue(sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}000004");
//        }

//        [Test]
//        public void TestLockTimeout()
//        {
//            ClearDBCache();
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql("create table test(sno varchar(50))");
//            var sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//            Assert.IsTrue(sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}000001");

//            //制造一个锁 30秒
//            var task1 = Task.Factory.StartNew(() =>
//            {
//                try
//                {
//                    var newDb = db.CreateNewDB();
//                    newDb.RunInTransaction(() =>
//                    {
//                        newDb.ExecuteSql(@"
//declare @result int=1;
//EXEC @result =sp_getAppLock @resource='dbutil:newsno:test_sno_SNO',@lockMode='Exclusive',@lockOwner='Transaction',@lockTimeout='60000';
//select @result");
//                        Thread.Sleep(30 * 1000);
//                    });
//                }
//                catch (Exception ex)
//                {
//                    //不应该报错
//                    throw ex;
//                }
//            });
//            var task2 = Task.Factory.StartNew(() =>
//            {
//                try
//                {
//                    Thread.Sleep(1000);
//                    var id = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//                    throw new Exception("应该报超时的错!");
//                }
//                catch (Exception ex)
//                {
//                    //锁超时信息
//                    Assert.IsTrue(ex.Message.Contains("20秒内"));
//                }
//            });
//            Task.WaitAll(task1, task2);
//        }
//        #endregion

//        #region SNO生成
//        [Test]
//        public void NewSNO_DBCacheTest()
//        {
//            ClearDBCache();
//            //准备测试表
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql(@"create table test(
//id int primary key,
//sno varchar(50),
//name varchar(50)
//)");
//            //单个生成
//            var sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//            Assert.IsTrue(sno == "SNO" + DateTime.Now.ToString("yyyyMMdd") + "000001");
//            sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//            Assert.IsTrue(sno == "SNO" + DateTime.Now.ToString("yyyyMMdd") + "000002");
//            //根据表中已有的sno,继续生成
//            var dic = new Dictionary<string, object>();
//            var id = db.NewId("test", "id");
//            dic.Add("id", id);
//            dic.Add("name", "xiaoming" + id);
//            dic.Add("sno", sno);
//            db.Insert("test", dic);
//            db.ResetSNO("test", "sno");
//            sno = db.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//            Assert.IsTrue(sno == "SNO" + DateTime.Now.ToString("yyyyMMdd") + "000003");
//            //根据缓存批量生成sno
//            var snos = db.NewSNOs("test", "sno", SerialFormat.CreateFast("SNO"), 5);
//            var expect = new List<string>() { $"SNO{DateTime.Now.ToString("yyyyMMdd")}000004", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000005", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000006", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000007", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000008" };
//            var expectStr = string.Join(",", expect);
//            var actStr = string.Join(",", snos);
//            Assert.IsTrue(expectStr == actStr);
//            //根据表中已有的id,继续批量生成
//            db.ResetSNO("test", "sno");
//            snos = db.NewSNOs("test", "sno", SerialFormat.CreateFast("SNO"), 5);
//            expect = new List<string>() { $"SNO{DateTime.Now.ToString("yyyyMMdd")}000003", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000004", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000005", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000006", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000007" };
//            expectStr = string.Join(",", expect);
//            actStr = string.Join(",", snos);
//            Assert.IsTrue(expectStr == actStr);
//            //直接从缓存中生成
//            db.Manage.TruncateTable("test", "dbo");
//            db.ResetSNO("test", "sno");
//            snos = db.NewSNOs("test", "sno", SerialFormat.CreateFast("SNO"), 5);
//            expect = new List<string>() { $"SNO{DateTime.Now.ToString("yyyyMMdd")}000001", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000002", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000003", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000004", $"SNO{DateTime.Now.ToString("yyyyMMdd")}000005" };
//            expectStr = string.Join(",", expect);
//            actStr = string.Join(",", snos);
//            Assert.IsTrue(expectStr == actStr);
//        }


//        [Test]
//        public void NewSNO_DBCacheConcurrencyTest()
//        {
//            ClearDBCache();
//            //准备测试表
//            db.Manage.DropTableIfExist("test");
//            db.ExecuteSql(@"create table test(
//id int primary key,
//sno varchar(50),
//name varchar(50)
//)");
//            var tasks = new List<Task>();
//            var snores = new System.Collections.Concurrent.ConcurrentQueue<(string sno, int threadid)>();
//            for (int i = 0; i < 100; i++)
//            {
//                tasks.Add(Task.Factory.StartNew(() =>
//                {
//                    try
//                    {
//                        var db2 = db.CreateNewDB();
//                        for (int j = 0; j < 100; j++)
//                        {
//                            var sno = db2.NewSNO("test", "sno", SerialFormat.CreateFast("SNO"));
//                            snores.Enqueue((sno, Thread.CurrentThread.ManagedThreadId));
//                        }
//                    }
//                    catch (Exception ex)
//                    {
//                        Debug.Write(ex?.Message + ex?.StackTrace);
//                        Debug.Fail(ex?.Message, ex?.StackTrace);
//                    }
//                }, TaskCreationOptions.LongRunning));
//            }
//            Task.WaitAll(tasks.ToArray());
//            var list = snores.ToList();
//            list = list.OrderByDescending(t => t.sno).ToList();
//            var expactCount = 100 * 100;
//            Assert.IsTrue(list.FirstOrDefault().sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}{expactCount.ToString().PadLeft(6, '0')}");
//            Assert.IsTrue(list.Count == expactCount);
//        }
//        #endregion
//    }
//}
